home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / msysjour / vol06 / 01 / kermit / wnkfns.c < prev    next >
C/C++ Source or Header  |  1990-12-31  |  36KB  |  1,530 lines

  1. /*
  2.  * WNKFNS.C
  3.  *
  4.  * Windows Kermit protocol support functions
  5.  *
  6.  * Copyright (c) 1990 by
  7.  * William S. Hall
  8.  * 3665 Benton Street, #66
  9.  * Santa Clara, CA 95051
  10.  *
  11.  */
  12.  
  13. /* The file is large, so these defines reduce the size of
  14.  * the symbol table generated by windows.h
  15.  */
  16. #define NOGDICAPMASKS     - CC_*, LC_*, PC_*, CP_*, TC_*, RC_
  17. #define NOVIRTUALKEYCODES - VK_*
  18. #define NOWINMESSAGES     - WM_*, EM_*, LB_*, CB_*
  19. #define NOWINSTYLES       - WS_*, CS_*, ES_*, LBS_*, SBS_*, CBS_*
  20. #define NOSYSMETRICS      - SM_*
  21. // #define NOMENUS          - MF_*
  22. #define NOICONS          - IDI_*
  23. #define NOKEYSTATES       - MK_*
  24. #define NOSYSCOMMANDS     - SC_*
  25. #define NORASTEROPS       - Binary and Tertiary raster ops
  26. // #define NOSHOWWINDOW      - SW_*
  27. #define OEMRESOURCE       - OEM Resource values
  28. #define NOATOM          - Atom Manager routines
  29. #define NOCLIPBOARD       - Clipboard routines
  30. #define NOCOLOR          - Screen colors
  31. // #define NOCTLMGR          - Control and Dialog routines
  32. // #define NODRAWTEXT          - DrawText() and DT_*
  33. // #define NOGDI          - All GDI defines and routines
  34. // #define NOKERNEL          - All KERNEL defines and routines
  35. // #define NOUSER          - All USER defines and routines
  36. // #define NOMB          - MB_* and MessageBox()
  37. // #define NOMEMMGR          - GMEM_*, LMEM_*, GHND, LHND, associated routines
  38. #define NOMETAFILE          - typedef METAFILEPICT
  39. #define NOMINMAX          - Macros min(a,b) and max(a,b)
  40. #define NOMSG          - typedef MSG and associated routines
  41. // #define NOOPENFILE          - OpenFile(), OemToAnsi, AnsiToOem, and OF_*
  42. #define NOSCROLL          - SB_* and scrolling routines
  43. #define NOSOUND          - Sound driver routines
  44. #define NOTEXTMETRIC      - typedef TEXTMETRIC and associated routines
  45. #define NOWH          - SetWindowsHook and WH_*
  46. #define NOWINOFFSETS      - GWL_*, GCL_*, associated routines
  47. // #define NOCOMM          - COMM driver routines
  48. #define NOKANJI          - Kanji support stuff.
  49. #define NOHELP            - Help engine interface.
  50. #define NOPROFILER          - Profiler interface.
  51. #define NODEFERWINDOWPOS  - DeferWindowPos routines
  52.  
  53. #include <windows.h>
  54. #include <stdlib.h>
  55. #include <stdio.h>
  56. #include <string.h>    
  57. #include <limits.h>
  58. #include <io.h>
  59. #include <sys\types.h>
  60. #include <sys\stat.h>
  61. #include "ascii.h"
  62. #include "wnkerm.h"
  63. #include "wnkdlg.h"
  64.  
  65. /* local function declarations */
  66. static    short    NEAR    krmWriteComm(int cid, BYTE *buf, int len);
  67. static    short    NEAR    krm_spack(char type, int n, int len, BYTE *data);
  68. static    void    NEAR    krm_errpkt(int msgnum);
  69. static    void    NEAR    krmSet8BitQuote(register BYTE sq);
  70. static    void    NEAR    krm_nak(void);
  71. static    void    NEAR    krmSetMenus(BOOL mode);
  72. static    void    NEAR    krmUpdateXferBox(WORD id, char *str);
  73. static    void    NEAR    krm_nxtpkt(void);
  74. static    int    NEAR    krm_decode(BYTE outbuf[], BYTE inbuf[], int *len);
  75. static    int    NEAR    krm_getpacket(register BYTE *str, register int len);
  76. static    WORD    NEAR    krm_chk1(WORD);
  77. static    WORD    NEAR    krm_chksum(BYTE *p, WORD init);
  78. static    DWORD    NEAR    krm_chksum3(BYTE *p, DWORD init);
  79. static    HANDLE    NEAR    krmOpenReceiveFile(BYTE *inbuf);
  80. BOOL    FAR    PASCAL    krmHideChildren(HWND hWnd, LONG lParam);
  81.  
  82. /*
  83.  * krm_getnextfile
  84.  *
  85.  * Parse the string of file names for the next one to send.
  86.  * The names themselves are delimited by a space.
  87.  */
  88. char * NEAR krm_getnextfile(BOOL first)
  89. {
  90.     char *type;
  91.  
  92.     if (Kermit.abort == KRM_BATCHABORT) {
  93.     Kermit.abort = 0;
  94.         return (char *)NULL;
  95.     }    
  96.  
  97.     type = (first ? Kermit.pFilelist : NULL);
  98.     return strtok(type, " ");
  99. }
  100.  
  101. /*
  102.  * krm_err
  103.  *
  104.  * Send an error packet to remote Kermit 
  105.  * and exit protocol with a message to user.
  106.  */
  107. void NEAR krm_err(int ref)
  108. {
  109.     krm_errpkt(ref);
  110.     krm_tend(ref);
  111. }
  112.  
  113. /*
  114.  * krm_sinit
  115.  *
  116.  * Send an init packet to remote Kermit
  117.  */
  118. int NEAR krm_sinit(void)
  119. {
  120.     BYTE data[40];
  121.     register int i = krm_rpar(data);
  122.     return (krm_spack('S', Kermit.seq, i, data));
  123. }
  124.  
  125. /*
  126.  * krm_sfile
  127.  *
  128.  * Send file name packet to remote Kermit
  129.  */
  130. int NEAR krm_sfile(void)
  131. {
  132.  
  133.     BYTE buf[KRM_MAXDATALEN + 1];
  134.     register int outlen;
  135.     int inlen;
  136.     int result;
  137.     struct stat fdata;
  138.  
  139.     if ((Kermit.hFile = OpenFile((LPSTR)Kermit.pFile,
  140.              (OFSTRUCT FAR *)&Kermit.fstruct, OF_READ)) != -1) {
  141.     stat(Kermit.fstruct.szPathName, &fdata);
  142.     Kermit.filesize = fdata.st_size ? fdata.st_size : Kermit.filesize;
  143.         Kermit.bytesmoved = 0;
  144.     if (KermParams.verbose) {
  145.             krmUpdateXferBox(IDD_KRM_FILENAME,
  146.               (strrchr(Kermit.fstruct.szPathName,'\\') + 1));
  147.         krmUpdateXferBox(IDD_KRM_BYTESMOVED,
  148.                  ultoa(Kermit.bytesmoved,buf,10));
  149.         krmUpdateXferBox(IDD_KRM_PERCENTAGE,itoa(0, buf, 10));
  150.     }
  151.     Kermit.maxsenddatalen = krm_sndinit.maxpktsize - 2 - Kermit.bctu;
  152.     inlen = strlen(Kermit.pFile);
  153.     outlen = krm_encode(buf, Kermit.pFile, Kermit.maxsenddatalen, &inlen);
  154.         krm_nxtpkt();
  155.         result = krm_spack('F',Kermit.seq, outlen, buf);
  156.     if (result < 0) {
  157.         krm_rclose(FALSE);
  158.         return result;
  159.     }
  160.     }
  161.     return (Kermit.hFile);
  162. }
  163.  
  164. /*
  165.  * krm_sdata
  166.  *
  167.  * Send encoded data packet to remote Kermit
  168.  */
  169. int NEAR krm_sdata(void)
  170. {
  171.     BYTE sbuf[KRM_MAXDATALEN + 1];
  172.     BYTE rbuf[KRM_MAXDATALEN + 1];
  173.     register int len;
  174.     register int numread;
  175.     int numrem = 0;
  176.     int result;
  177.     BYTE *sptr;
  178.     int numcoded = 0;
  179.     int maxlen = Kermit.maxsenddatalen;
  180.  
  181.     for (sptr = sbuf; (numrem == 0) && (numcoded < maxlen); 
  182.               sptr += len, maxlen -= len) {
  183.     if ((numread = read(Kermit.hFile, rbuf, sizeof(rbuf) - 1)) > 0) {
  184.         numrem = numread;
  185.         numcoded += len = krm_encode(sptr, rbuf, maxlen, &numrem);
  186.         Kermit.bytesmoved = lseek(Kermit.hFile, -(LONG)numrem, SEEK_CUR);
  187.     }
  188.     else
  189.         break;
  190.     }
  191.     if ((numread >= 0) && (numcoded > 0)) {
  192.         krm_nxtpkt();
  193.         result = krm_spack('D', Kermit.seq, numcoded, sbuf);
  194.     if (result > 0) {
  195.         if (KermParams.verbose) {
  196.             krmUpdateXferBox(IDD_KRM_BYTESMOVED,
  197.                   ultoa(Kermit.bytesmoved,sbuf,10));
  198.             krmUpdateXferBox(IDD_KRM_PERCENTAGE,
  199.             ultoa(Kermit.bytesmoved * 100 / Kermit.filesize, sbuf, 10));
  200.         }
  201.     }
  202.     return result;
  203.     }
  204.     return numread;
  205. }
  206.  
  207. /*
  208.  * krm_seof
  209.  *
  210.  * Send end of file packet to remote Kermit
  211.  */
  212. int NEAR krm_seof(char *s)
  213. {
  214.  
  215.     if (krm_rclose(FALSE)) {
  216.         krm_nxtpkt();
  217.         return (krm_spack('Z', Kermit.seq, strlen(s), s));
  218.     }
  219.     return (-1);
  220. }
  221.  
  222. /*
  223.  * krm_seot
  224.  *
  225.  * Send end of transmission (break) packet to remote Kermit
  226.  */
  227. int NEAR krm_seot(void)
  228. {
  229.     krm_nxtpkt();
  230.     return (krm_spack('B', Kermit.seq, 0, ""));
  231. }
  232.  
  233. /*
  234.  * krm_encode
  235.  *
  236.  * Encode a buffer quoting control characters,
  237.  * adding run length encoding and eight bit
  238.  * quoting if requested, while packing buffer to its maximum.
  239.  */
  240. int NEAR krm_encode(BYTE *outbuf, BYTE *inbuf, int maxlen, int *inlen)
  241. {
  242.     register int i, j;
  243.     BYTE t, t7;
  244.     BYTE b8;
  245.     int rpt = 0;
  246.     int back = 1;
  247.     int extra = 0;
  248.  
  249.     for (i = 0, j = 0; (i < maxlen) && (j < *inlen); ) {
  250.     t = inbuf[j++];
  251.     t7 = t & (BYTE)0x7f;
  252.     b8 = t & (BYTE)0x80;
  253.     
  254.     if (Kermit.rptflag) {
  255.         for (rpt = 0; (rpt < 93) && (j < *inlen); rpt++, j++)
  256.             if (t != inbuf[j])
  257.             break;
  258.         if (rpt == 1) {
  259.         j -= 1;
  260.         rpt = 0;
  261.         }
  262.         back = 1 + rpt;
  263.         extra = rpt ? 2 : 0;
  264.         if (rpt > 1)
  265.         rpt += 1;
  266.     }
  267.     if ((t7 < SP) || (t7 == DEL)) {
  268.         if (Kermit.ebqflag && b8) {
  269.         if (i < (maxlen - 2 - extra)) {
  270.             if (rpt) {
  271.             outbuf[i++] = krm_sndinit.rpquote;
  272.             outbuf[i++] = (BYTE)tochar(rpt);
  273.             }
  274.             outbuf[i++] = krm_sndinit.ebquote;
  275.             outbuf[i++] = krm_sndinit.quote;
  276.             outbuf[i++] = (BYTE)ctl(t7);
  277.         }
  278.         else {
  279.             j -= back;
  280.             break;
  281.         }
  282.         }
  283.         else {
  284.         if (i < (maxlen - 1 - extra)) {
  285.             if (rpt) {
  286.             outbuf[i++] = krm_sndinit.rpquote;
  287.             outbuf[i++] = (BYTE)tochar(rpt);
  288.             }
  289.             outbuf[i++] = krm_sndinit.quote;
  290.             outbuf[i++] = (BYTE)ctl(t);
  291.         }
  292.         else {
  293.             j -= back;
  294.             break;
  295.         }
  296.         }
  297.     }
  298.     else if (t7 == krm_sndinit.rpquote) {
  299.         if (Kermit.rptflag) {
  300.             if (Kermit.ebqflag) {
  301.             if (b8) {
  302.                 if (i < (maxlen - 2 - extra)) {
  303.                     if (rpt) {
  304.                     outbuf[i++] = krm_sndinit.rpquote;
  305.                     outbuf[i++] = (BYTE)tochar(rpt);
  306.                     }
  307.                     outbuf[i++] = krm_sndinit.ebquote;
  308.                     outbuf[i++] = krm_sndinit.quote;
  309.                     outbuf[i++] = t7;
  310.                 }
  311.                 else {
  312.                 j -= back;
  313.                 break;
  314.                 }
  315.             }
  316.             else {
  317.                 if (i < (maxlen - 1 - extra)) {
  318.                     if (rpt) {
  319.                     outbuf[i++] = krm_sndinit.rpquote;
  320.                     outbuf[i++] = (BYTE)tochar(rpt);
  321.                     }
  322.                     outbuf[i++] = krm_sndinit.quote;
  323.                     outbuf[i++] = t7;
  324.                 }            
  325.                 else {
  326.                 j -= back;
  327.                 break;
  328.                 }
  329.             }
  330.             }
  331.             else {
  332.             if (i < (maxlen - 1 - extra)) {
  333.                 if (rpt) {
  334.                     outbuf[i++] = krm_sndinit.rpquote;
  335.                 outbuf[i++] = (BYTE)tochar(rpt);
  336.                 }
  337.             outbuf[i++] = krm_sndinit.quote;
  338.                     outbuf[i++] = t;
  339.             }
  340.             else {
  341.                 j -= back;
  342.                 break;
  343.             }
  344.             }
  345.         }
  346.         else {
  347.             if (Kermit.ebqflag && b8) {
  348.             if (i < (maxlen - 1 - extra)) {
  349.                 outbuf[i++] = krm_sndinit.ebquote;
  350.                 outbuf[i++] = t7;
  351.             }
  352.             else {
  353.                 j -= back;
  354.                 break;
  355.             }
  356.             }
  357.             else {
  358.             if (i < (maxlen - extra)) {
  359.                 outbuf[i++] = t;
  360.             }
  361.             else {
  362.                 j -= back;
  363.                 break;
  364.             }
  365.             }
  366.         }
  367.     }
  368.     else if (t7 == krm_sndinit.ebquote) {
  369.         if (Kermit.ebqflag) {
  370.         if (b8) {
  371.             if (i < (maxlen - 2 - extra)) {
  372.                 if (rpt) {
  373.                 outbuf[i++] = krm_sndinit.rpquote;
  374.                 outbuf[i++] = (BYTE)tochar(rpt);
  375.                 }
  376.                 outbuf[i++] = krm_sndinit.ebquote;
  377.                 outbuf[i++] = krm_sndinit.quote;
  378.                 outbuf[i++] = t7;
  379.             }
  380.             else {
  381.             j -= back;
  382.             break;
  383.             }
  384.         }
  385.         else {
  386.             if (i < (maxlen - 1 - extra)) {
  387.                 if (rpt) {
  388.                 outbuf[i++] = krm_sndinit.rpquote;
  389.                 outbuf[i++] = (BYTE)tochar(rpt);
  390.                 }
  391.                 outbuf[i++] = krm_sndinit.quote;
  392.                 outbuf[i++] = t7;
  393.             }            
  394.             else {
  395.             j -= back;
  396.             break;
  397.             }
  398.         }
  399.         }
  400.         else {
  401.         if (i < (maxlen - extra)) {
  402.             if (rpt) {
  403.                 outbuf[i++] = krm_sndinit.rpquote;
  404.             outbuf[i++] = (BYTE)tochar(rpt);
  405.             }
  406.                 outbuf[i++] = t;
  407.         }
  408.         else {
  409.             j -= back;
  410.             break;
  411.         }
  412.         }
  413.     }
  414.     else if (t7 == krm_sndinit.quote) {
  415.         if (Kermit.ebqflag && b8) {
  416.         if (i < (maxlen - 2 - extra)) {
  417.             if (rpt) {
  418.                 outbuf[i++] = krm_sndinit.rpquote;
  419.             outbuf[i++] = (BYTE)tochar(rpt);
  420.             }
  421.             outbuf[i++] = krm_sndinit.ebquote;
  422.             outbuf[i++] = krm_sndinit.quote;
  423.             outbuf[i++] = t7;
  424.         }
  425.         else {
  426.             j -= back;
  427.             break;
  428.         }
  429.         }
  430.         else {
  431.         if (i < (maxlen - 1 - extra)) {
  432.             if (rpt) {
  433.                 outbuf[i++] = krm_sndinit.rpquote;
  434.             outbuf[i++] = (BYTE)tochar(rpt);
  435.             }
  436.             outbuf[i++] = krm_sndinit.quote;
  437.             outbuf[i++] = t;
  438.         }
  439.         else {
  440.             j -= back;
  441.             break;
  442.         }
  443.         }
  444.     }    
  445.     else {
  446.         if (Kermit.ebqflag && b8) {
  447.         if (i < (maxlen - 1 - extra)) {
  448.             if (rpt) {
  449.                 outbuf[i++] = krm_sndinit.rpquote;
  450.             outbuf[i++] = (BYTE)tochar(rpt);
  451.             }
  452.             outbuf[i++] = krm_sndinit.ebquote;
  453.             outbuf[i++] = t7;
  454.         }
  455.         else {
  456.             j -= back;
  457.             break;
  458.         }
  459.         }
  460.         else {
  461.         if (i < (maxlen - extra)) {
  462.             if (rpt) {
  463.                 outbuf[i++] = krm_sndinit.rpquote;
  464.             outbuf[i++] = (BYTE)tochar(rpt);
  465.             }
  466.             outbuf[i++] = t;
  467.         }
  468.         else {
  469.             j -= back;
  470.             break;
  471.         }
  472.         }
  473.     }
  474.     }
  475.     outbuf[i] = NUL;
  476.     *inlen -= j;
  477.     return i;
  478. }
  479.  
  480. /*
  481.  * krm_rcvfile
  482.  *
  483.  * Get a file name from remote Kermit and open
  484.  * it for writing.
  485.  */
  486. BOOL NEAR krm_rcvfil(void)
  487. {
  488.     BYTE buf[KRM_MAXPACKETSIZE + 1];
  489.     int len = krm_rcvpkt.len;
  490.     
  491.     krm_decode(buf, krm_rcvpkt.data, &len);
  492.     if (KermParams.verbose)
  493.         krmUpdateXferBox(IDD_KRM_FILENAME, buf);
  494.  
  495.     if ((Kermit.hFile = krmOpenReceiveFile(buf)) != -1) {
  496.         Kermit.bytesmoved = 0;
  497.     Kermit.pFile = strrchr(Kermit.fstruct.szPathName,'\\') + 1;
  498.     if (KermParams.verbose) {
  499.             krmUpdateXferBox(IDD_KRM_SAVENAME, Kermit.pFile);
  500.         krmUpdateXferBox(IDD_KRM_BYTESMOVED, 
  501.                   ultoa(Kermit.bytesmoved, buf, 10));
  502.     }
  503.     return TRUE;
  504.     }
  505.     return FALSE;
  506. }
  507.  
  508. /*
  509.  * krm_rcvdata
  510.  *
  511.  * Get a data packet from remote Kermit and save
  512.  * to a file
  513.  */
  514. BOOL NEAR krm_rcvdata(void)
  515. {
  516.     BYTE buf[KRM_MAXPACKETSIZE + 1];
  517.     register int outlen;
  518.     int startlen, inlen;
  519.     register BYTE *ptr;
  520.  
  521.     for (ptr = krm_rcvpkt.data, startlen = inlen = krm_rcvpkt.len;
  522.      inlen > 0; ptr += (startlen - inlen), startlen = inlen) {
  523.         outlen = krm_decode(buf, ptr, &inlen);
  524.         if (write(Kermit.hFile, buf, outlen) == -1)
  525.         return FALSE;
  526.        Kermit.bytesmoved += (DWORD)outlen;
  527.     }
  528.     if (KermParams.verbose)
  529.         krmUpdateXferBox(IDD_KRM_BYTESMOVED, ultoa(Kermit.bytesmoved, buf, 10));
  530.     return TRUE;
  531. }
  532.  
  533. /*
  534.  * krm_rclose
  535.  *
  536.  * Close a file under normal or error conditions
  537.  * deleting a partially received file if necessary.
  538.  */
  539. BOOL NEAR krm_rclose(BOOL remove)
  540. {
  541.     if (Kermit.hFile > 0) {
  542.         if (close(Kermit.hFile) == 0) {
  543.         Kermit.hFile = 0;
  544.         if (remove && 
  545.         KermParams.DiscardPartialFile && 
  546.         (Kermit.mode == IDM_KRM_RECEIVE)) {
  547.             unlink(Kermit.fstruct.szPathName);
  548.         }
  549.             return TRUE;
  550.     }
  551.      }
  552.      else if (Kermit.hFile == 0)
  553.     return TRUE;
  554.  
  555.      return FALSE;
  556. }
  557.  
  558. /*
  559.  * krm_decode
  560.  *
  561.  * Decode control, eight-bit, and repeat character quote characters
  562.  * in a received data packet.
  563.  */
  564. static int NEAR krm_decode(BYTE outbuf[], BYTE inbuf[], int *len)
  565. {
  566.     BYTE a, a7;
  567.     register int i,j;
  568.     BYTE bitset;
  569.     int rpt;
  570.  
  571.     for (i = 0, j = 0; (j < *len) && (i < KRM_MAXPACKETSIZE); ) {
  572.     rpt = 1;
  573.     a = inbuf[j++];
  574.     if (Kermit.rptflag) {
  575.         if (a == krm_rcvinit.rpquote) {
  576.         rpt = unchar(inbuf[j++]);
  577.         if (rpt <= (KRM_MAXPACKETSIZE - i))
  578.             a = inbuf[j++];
  579.         else {    
  580.             j -= 2;
  581.             break;
  582.         }
  583.         }
  584.     }
  585.     bitset = 0;
  586.         if (Kermit.ebqflag) {
  587.         if (a == krm_rcvinit.ebquote) {
  588.         a = inbuf[j++];
  589.         bitset = 0x80;
  590.         }
  591.     }
  592.     if (a == krm_rcvinit.quote) {
  593.         a = inbuf[j++];
  594.         a7 = a & (BYTE)0x7f;
  595.         if ((a7 >= '?') && ( a7 <= '_'))
  596.             a = (BYTE)ctl(a);
  597.     }
  598.     a |= bitset;
  599.     for ( ; rpt > 0; rpt--)
  600.         outbuf[i++] = a;
  601.     }
  602.     *len -= j;
  603.     outbuf[i] = NUL;
  604.     return i;
  605. }
  606.  
  607. /*
  608.  * krm_rpack
  609.  *
  610.  * Read and call routines to build an incoming packet.
  611.  */
  612. int NEAR krm_rpack(void)
  613. {
  614.     register int type;
  615.  
  616.     switch(krm_rcvpkt.state) {
  617.     case PS_START:
  618.         if (KermParams.Timer)
  619.         SetTimer(Kermit.hWnd, KRM_WAITPACKET, 
  620.              krm_sndinit.timeout * 1000, Kermit.fpTimer);
  621.         krm_rcvpkt.state += 1;
  622.  
  623.     default:
  624.         if (*krmBuflen)
  625.         *krmBuflen = krm_getpacket(krmBufptr, *krmBuflen);
  626.         if (krm_rcvpkt.state < PS_DONE) {
  627.         type = '$';
  628.         break;
  629.         }
  630.  
  631.     case PS_DONE:
  632.         krm_rcvpkt.state = PS_START;
  633.         if (KermParams.Timer)
  634.         KillTimer(Kermit.hWnd, KRM_WAITPACKET);
  635.         type = krm_rcvpkt.type;
  636.  
  637.     }
  638.     return type;
  639. }
  640.  
  641. /*
  642.  * krm_getpacket
  643.  *
  644.  * Attempt to build as much as possible of a complete incoming
  645.  * packet.
  646.  */        
  647. static int NEAR krm_getpacket(register BYTE *str, register int len)
  648. {
  649.     static BYTE buf[5];
  650.     WORD chk;
  651.     DWORD chk3;
  652.  
  653.     for ( ; len > 0; len--, str++) {
  654.  
  655.     switch(krm_rcvpkt.state) {
  656.  
  657.         case PS_SYNCH:
  658.         if (*str == krm_rcvinit.mark) {
  659.             krm_rcvpkt.data_count = 0;
  660.             krm_rcvpkt.chk_count = 0;
  661.             krm_rcvpkt.data[0] = 0;
  662.             krm_rcvpkt.state++;
  663.         }
  664.         break;
  665.  
  666.         case PS_LEN:
  667.         krm_rcvpkt.len = unchar(*str) - 2 - Kermit.bctu;
  668.         if (krm_rcvpkt.len > KRM_MAXDATALEN)
  669.             krm_rcvpkt.len = KRM_MAXDATALEN;
  670.         buf[0] = *str;
  671.         krm_rcvpkt.state++;
  672.         break;
  673.  
  674.         case PS_NUM:
  675.         krm_rcvpkt.seq = unchar(*str);
  676.         buf[1] = *str;
  677.         krm_rcvpkt.state++;
  678.         break;
  679.  
  680.         case PS_TYPE:
  681.         krm_rcvpkt.type = *str;
  682.         buf[2] = *str;
  683.         buf[3] = 0;
  684.         if (krm_rcvpkt.len)
  685.             krm_rcvpkt.state++;
  686.         else
  687.             krm_rcvpkt.state = PS_CHK;
  688.         break;
  689.  
  690.         case PS_DATA:
  691.         if (krm_rcvpkt.data_count < krm_rcvpkt.len) {
  692.             krm_rcvpkt.data[krm_rcvpkt.data_count++] = *str;
  693.             break;
  694.         }
  695.         else {
  696.             krm_rcvpkt.data[krm_rcvpkt.data_count] = NUL;
  697.             krm_rcvpkt.state++;
  698.             /* fall thru */
  699.         }
  700.  
  701.         case PS_CHK:
  702.         if (krm_rcvpkt.chk_count < Kermit.bctu) {
  703.             krm_rcvpkt.rchksum[krm_rcvpkt.chk_count++] = *str;
  704.             break;
  705.         }
  706.         switch(Kermit.bctu) {
  707.             case 1:
  708.             default:
  709.                 chk = krm_chk1(krm_chksum(krm_rcvpkt.data, 
  710.                        krm_chksum(buf,0)));
  711.                 if (chk != (WORD)unchar(krm_rcvpkt.rchksum[0]))
  712.                 krm_rcvpkt.type = 'Q';
  713.             break;
  714.             case 2:
  715.             chk = ((WORD)unchar(krm_rcvpkt.rchksum[0]) << 6) | 
  716.                    (WORD)unchar(krm_rcvpkt.rchksum[1]);
  717.             if (chk != krm_chksum(krm_rcvpkt.data, 
  718.                               krm_chksum(buf,0)))
  719.                 krm_rcvpkt.type = 'Q';
  720.             break;
  721.             case 3:
  722.             chk3 = ((WORD)unchar(krm_rcvpkt.rchksum[0]) << 12) |
  723.                 ((WORD)unchar(krm_rcvpkt.rchksum[1]) << 6) |
  724.                 (WORD)unchar(krm_rcvpkt.rchksum[2]);
  725.             if (chk3 != krm_chksum3(krm_rcvpkt.data, 
  726.                         krm_chksum3(buf,0)))
  727.                 krm_rcvpkt.type = 'Q';
  728.             break;
  729.         }        
  730.         krm_rcvpkt.state++;
  731.         break;
  732.  
  733.         case PS_DONE:
  734.         if (*str == krm_rcvinit.eol)
  735.             len--;
  736.         return len;
  737.         break;
  738.     }
  739.     }
  740.     return len;
  741. }
  742.  
  743. /*
  744.  * krm_tinit
  745.  *
  746.  * Initialize for file transfer
  747.  */
  748. void NEAR krm_tinit(void)
  749. {
  750.  
  751.     DCB mydcb;
  752.     FARPROC fp;
  753.  
  754.   // Get data from KermParams
  755.     Kermit.bctr = KermParams.BlockCheckType;
  756.     Kermit.bctu = 1;
  757.  
  758.   // Get data from sndparams
  759.     krm_sndinit.mark = sndparams.mark;
  760.     krm_sndinit.maxpktsize = sndparams.maxpktsize;
  761.     krm_sndinit.timeout = sndparams.timeout;
  762.     krm_sndinit.padcount = sndparams.padcount;
  763.     krm_sndinit.padchar = sndparams.padchar;
  764.     krm_sndinit.eol = sndparams.eol;
  765.     krm_sndinit.quote = sndparams.quote;
  766.  
  767.   // Get data from rcvparams;
  768.     krm_rcvinit.mark = rcvparams.mark;
  769.     krm_rcvinit.maxpktsize = rcvparams.maxpktsize;
  770.     krm_rcvinit.timeout = rcvparams.timeout;
  771.     krm_rcvinit.padcount = rcvparams.padcount;
  772.     krm_rcvinit.padchar = rcvparams.padchar;
  773.     krm_rcvinit.eol = rcvparams.eol;
  774.     krm_rcvinit.quote = rcvparams.quote;
  775.  
  776.   // Set other values
  777.     krm_sndinit.ebquote = 'N';
  778.     krm_sndinit.rpquote = KermParams.rpquote;
  779.  
  780.  // Check parity and set eight-bit request
  781.     GetCommState(*krmcid, &mydcb);
  782.     if (mydcb.ByteSize == 8)
  783.     krm_rcvinit.ebquote = 'Y';
  784.     else
  785.     krm_rcvinit.ebquote = KermParams.ebquote;
  786.     krm_rcvinit.rpquote = KermParams.rpquote;
  787.  
  788.  // If verbose, prepare a dialog box to show transfer and hide child windows
  789.     if (KermParams.verbose) {
  790.     fp = MakeProcInstance((FARPROC)krmHideChildren, Kermit.hInst);
  791.     EnumChildWindows(Kermit.hWnd, fp, (LONG)SW_HIDE);
  792.     FreeProcInstance(fp);
  793.         Kermit.hWndXfer = CreateDialog(Kermit.hInst, 
  794.                        MAKEINTRESOURCE(DT_KRM_XFER),
  795.                        Kermit.hWnd, Kermit.fpXfer);
  796.     }
  797.     else
  798.     Kermit.hWndXfer = NULL;
  799.  
  800.   // If delay before first send packet, then set timer
  801.     if (KermParams.SendDelay) {
  802.     SetTimer(Kermit.hWnd, KRM_WAITSEND, KermParams.SendDelay * 1000, 
  803.                Kermit.fpTimer);
  804.     Kermit.delay = TRUE;
  805.     }
  806.  
  807.   // Set more parameters
  808.     krm_rcvpkt.state = PS_START;
  809.     krm_rcvpkt.seq = 0;
  810.  
  811.     krm_sndpkt[0] = NUL;
  812.  
  813.     Kermit.seq = 0;
  814.     Kermit.retries = 0;
  815.     Kermit.totalretries = 0;
  816.     Kermit.bytesmoved = 0L;
  817.     Kermit.packetcount = 0L;
  818.     Kermit.filesize = ULONG_MAX;
  819.     Kermit.abort = 0;
  820.     Kermit.InTransfer = TRUE;
  821.     Kermit.hFile = 0;
  822.     Kermit.hFilelist = NULL;
  823.     Kermit.pFile = NULL;
  824.     Kermit.ebqflag = FALSE;
  825.     Kermit.rptflag = FALSE;
  826.     Kermit.maxsenddatalen = krm_sndinit.maxpktsize - 5;   /* worst case */
  827.  
  828.     krmSetMenus(TRUE);
  829.     krmFlushQue();
  830.  
  831. }
  832.  
  833. /*
  834.  * krmSetMenus
  835.  *
  836.  * Toggle menus according to whether Kermit is starting or ending
  837.  */
  838. static void NEAR krmSetMenus(BOOL mode)
  839. {
  840.     HMENU hMenu = GetMenu(Kermit.hWnd);
  841.  
  842.     EnableMenuItem(hMenu, IDM_KRM_RECEIVE, mode ? MF_GRAYED : MF_ENABLED);
  843.     EnableMenuItem(hMenu, IDM_KRM_SEND, mode ? MF_GRAYED : MF_ENABLED);
  844.     EnableMenuItem(hMenu, IDM_KRM_PROTOCOL, mode ? MF_GRAYED : MF_ENABLED);
  845.     EnableMenuItem(hMenu, IDM_KRM_PACKETS, mode ? MF_GRAYED : MF_ENABLED);
  846.     EnableMenuItem(hMenu, IDM_KRM_CANCEL, mode ? MF_ENABLED : MF_GRAYED);
  847.     EnableMenuItem(hMenu, IDM_KRM_FILEABORT, mode ? MF_ENABLED : MF_GRAYED);
  848.     EnableMenuItem(hMenu, IDM_KRM_BATCHABORT, mode ? MF_ENABLED : MF_GRAYED);
  849.     EnableMenuItem(hMenu, IDM_KRM_ERRORABORT, mode ? MF_ENABLED : MF_GRAYED);
  850.  
  851. }
  852.  
  853. /*
  854.  * krm_tend
  855.  *
  856.  * Terminate Kermit file transfer and clean up
  857.  */
  858. void NEAR krm_tend(int code)
  859. {
  860.  
  861.     FARPROC fp;
  862.  
  863.     KillTimer(Kermit.hWnd, KRM_WAITPACKET);
  864.     KillTimer(Kermit.hWnd, KRM_WAITSEND);
  865.  
  866.     if (Kermit.hFilelist) {
  867.     LocalUnlock(Kermit.hFilelist);
  868.     LocalFree(Kermit.hFilelist);
  869.     }
  870.     Kermit.InTransfer = FALSE;
  871.     krmSetMenus(FALSE);
  872.     if (KermParams.Bell)
  873.     MessageBeep(code);
  874.     krmShowMessage(code);
  875.  
  876.     InvalidateRect(Kermit.hWnd, NULL, TRUE);
  877.  
  878.     if (KermParams.verbose) {
  879.         if (IsWindow(Kermit.hWndXfer))
  880.             DestroyWindow(Kermit.hWndXfer);
  881.     fp = MakeProcInstance((FARPROC)krmHideChildren, Kermit.hInst);
  882.     EnumChildWindows(Kermit.hWnd, fp, (LONG)SW_RESTORE);
  883.     FreeProcInstance(fp);
  884.     }
  885. }
  886.  
  887. /*
  888.  * krmShutdown
  889.  *
  890.  * Terminate Kermit and release any used resources.
  891.  * If in the middle of a tranfer, ask if user really
  892.  * wants to shut down.  This function should be called
  893.  * at WM_CLOSE and WM_QUERYENDSESSION in the terminal program.  
  894.  * If it returns anything but IDYES, then the terminal
  895.  * program should not terminate.
  896.  */
  897. int FAR krmShutdown()
  898. {
  899.     char buf[80];
  900.     char appname[20];
  901.     int result = IDYES;
  902.  
  903.     if (Kermit.InTransfer) {
  904.         LoadString(Kermit.hInst, IDS_KRM_KERMIT, appname, sizeof(appname));
  905.         LoadString(Kermit.hInst, IDS_KRM_QUIT, (LPSTR)buf, sizeof(buf));
  906.         result = MessageBox(GetFocus(),buf,appname,MB_ICONQUESTION | MB_YESNO);
  907.  
  908.         if (result == IDYES) {
  909.             krm_errpkt(IDS_KRM_CANCELLED);
  910.             krm_rclose(TRUE);
  911.  
  912.             KillTimer(Kermit.hWnd, KRM_WAITPACKET);
  913.             KillTimer(Kermit.hWnd, KRM_WAITSEND);
  914.  
  915.             if (KermParams.verbose)
  916.                 if (IsWindow(Kermit.hWndXfer))
  917.                     DestroyWindow(Kermit.hWndXfer);
  918.     
  919.         }
  920.     }
  921.     if (result == IDYES) {
  922.         FreeProcInstance(Kermit.fpTimer);
  923.         FreeProcInstance(Kermit.fpXfer);
  924.     }
  925.     return result;
  926. }
  927.  
  928. /*
  929.  * krm_spack
  930.  *
  931.  * Assemble a packet for transmission
  932.  */    
  933. short NEAR krm_spack(char type, int n, int len, BYTE *data)
  934. {
  935.     register int i, j;
  936.     WORD chk;
  937.     DWORD chk3;
  938.  
  939.     i = 0;
  940.  
  941.     krm_sndpkt[i++] = krm_sndinit.mark;
  942.     krm_sndpkt[i++] = (BYTE)tochar(len + 2 + Kermit.bctu);
  943.     krm_sndpkt[i++] = (BYTE)tochar(n);
  944.     krm_sndpkt[i++] = type;
  945.  
  946.     for (j = len; j > 0; j--)
  947.     krm_sndpkt[i++] = *data++;
  948.  
  949.     krm_sndpkt[i] = NUL;
  950.  
  951.     switch(Kermit.bctu) {
  952.     case 1:
  953.     default:
  954.         krm_sndpkt[i++] = 
  955.         (BYTE)tochar(krm_chk1(krm_chksum(krm_sndpkt+1,0)));
  956.         break;
  957.     case 2:
  958.         chk = krm_chksum(krm_sndpkt+1,0);
  959.         krm_sndpkt[i++] = (BYTE)tochar((chk >> 6) & 077);
  960.         krm_sndpkt[i++] = (BYTE)tochar(chk & 077);
  961.         break;
  962.     case 3:
  963.         chk3 = krm_chksum3(krm_sndpkt+1,0L);
  964.         krm_sndpkt[i++] = (BYTE)tochar((chk3 >> 12) & 017);
  965.         krm_sndpkt[i++] = (BYTE)tochar((chk3 >> 6) & 077);
  966.         krm_sndpkt[i++] = (BYTE)tochar(chk3 & 077);
  967.         break;
  968.     }
  969.     krm_sndpkt[i++] = krm_sndinit.eol;
  970.     krm_sndpkt[i] = NUL;
  971.  
  972.     return (krmWriteComm(*krmcid, krm_sndpkt, i));
  973.     
  974. }
  975.  
  976. /*
  977.  * krm_chk1
  978.  *
  979.  * Perform a 1-byte check sum calculation on a value
  980.  */
  981. static WORD NEAR krm_chk1(WORD s)
  982. {
  983.  
  984.     return (((s & 192) >> 6) + s) & 63;
  985.  
  986. }
  987.  
  988. /*
  989.  * krm_chksum
  990.  *
  991.  * Perform a 2-byte check sum calculation on a string.  The
  992.  * initial value of the checksum may be specified.
  993.  */
  994. static WORD NEAR krm_chksum(BYTE *p, WORD init)
  995. {
  996.     WORD s;
  997.  
  998.     for (s = init; *p != NUL; *p++)
  999.     s += *p;
  1000.  
  1001.     return (s & 07777);
  1002. }
  1003.  
  1004. /*
  1005.  * krm_chksum3
  1006.  *
  1007.  * Perform a 3-byte CRC checksum on a string.  The initial
  1008.  * value of the checksum may be specified.
  1009.  */
  1010. static DWORD NEAR krm_chksum3(BYTE *p, DWORD init)
  1011. {
  1012.     DWORD crc = init;
  1013.     WORD c, q;
  1014.  
  1015.     while (c = *p++) {
  1016.     q = (WORD)((crc ^ c) & 017);
  1017.     crc = (crc >> 4) ^ (q * 010201);
  1018.     q = (WORD)((crc ^ (c >> 4)) & 017);
  1019.     crc = (crc >> 4) ^ (q * 010201);
  1020.     }
  1021.     return crc;
  1022. }
  1023.  
  1024. /*
  1025.  * krm_ack
  1026.  *
  1027.  * Send an ack packet, possibly containing data
  1028.  */
  1029. void NEAR krm_ack(short len, BYTE * str)
  1030. {
  1031.  
  1032.     krm_spack('Y', Kermit.seq, len, str);
  1033.     krm_nxtpkt();
  1034. }
  1035.  
  1036. /*
  1037.  * krm_nxtpkt
  1038.  *
  1039.  * Bump the packet sequence number
  1040.  * and display the information if requested.
  1041.  */
  1042. static void NEAR krm_nxtpkt(void)
  1043. {
  1044.     char buf[40];
  1045.  
  1046.     Kermit.seq = (Kermit.seq + 1) & 63;
  1047.     Kermit.packetcount += 1;
  1048.     if (KermParams.verbose)
  1049.         krmUpdateXferBox(IDD_KRM_PACKETS, ultoa(Kermit.packetcount, buf, 10));
  1050.     if (IsIconic(Kermit.hWnd))
  1051.         InvalidateRect(Kermit.hWnd, NULL, FALSE);
  1052. }
  1053.  
  1054. /*
  1055.  * krm_rpar
  1056.  *
  1057.  * Prepare our parameters for transmission to
  1058.  * the remote Kermit
  1059.  */
  1060. int NEAR krm_rpar(BYTE data[])
  1061. {
  1062.     register int i = 0;
  1063.  
  1064.     data[i++] = (BYTE)tochar(krm_rcvinit.maxpktsize);
  1065.     data[i++] = (BYTE)tochar(krm_rcvinit.timeout);
  1066.     data[i++] = (BYTE)tochar(krm_rcvinit.padcount);
  1067.     data[i++] = (BYTE)ctl(krm_rcvinit.padchar);
  1068.     data[i++] = (BYTE)tochar(krm_rcvinit.eol);
  1069.     data[i++] = krm_rcvinit.quote;
  1070.     data[i++] = krm_rcvinit.ebquote;
  1071.     data[i++] = (BYTE)(Kermit.bctr + '0');
  1072.     data[i++] = krm_rcvinit.rpquote;
  1073.     data[i] = NUL;
  1074.  
  1075.     return i;
  1076. }
  1077.  
  1078. /*
  1079.  * krmSet8BitQuote
  1080.  * 
  1081.  * Negotiate eight-bit quoting with remote Kermit
  1082.  */
  1083. static void NEAR krmSet8BitQuote(register BYTE sq)
  1084. {
  1085.  
  1086.     krm_sndinit.ebquote = sq;
  1087.  
  1088.     switch(sq) {
  1089.     case 'N':
  1090.         Kermit.ebqflag = FALSE;
  1091.         break;
  1092.  
  1093.     case 'Y':
  1094.         if (krm_rcvinit.ebquote == KermParams.ebquote) {
  1095.         krm_sndinit.ebquote = krm_rcvinit.ebquote;
  1096.         Kermit.ebqflag = TRUE;
  1097.         }
  1098.         break;
  1099.  
  1100.     default:
  1101.         if (((sq > 32) && (sq < 63)) || ((sq > 95) && (sq < 127))) {
  1102.         krm_rcvinit.ebquote = sq;
  1103.         Kermit.ebqflag = TRUE;
  1104.         }
  1105.         else
  1106.         Kermit.ebqflag = FALSE;
  1107.     }
  1108. }
  1109.  
  1110. /* 
  1111.  * krm_spar
  1112.  *
  1113.  * Read remote Kermit's parameters and save them to
  1114.  * a KRMSENDINIT structure to be used for forming outbound
  1115.  * packets
  1116.  */
  1117. void NEAR krm_spar(BYTE *data, short len)
  1118. {
  1119.     register int i;
  1120.     register int x;
  1121.  
  1122.     for (i = 0; i < len; i++) {
  1123.     switch(i) {
  1124.         case 0:
  1125.         x = unchar(data[i]);
  1126.         if ((x < KRM_MINPACKETSIZE) || (x > KRM_MAXPACKETSIZE))
  1127.             x = KRM_DEFPACKETSIZE;
  1128.         krm_sndinit.maxpktsize = x;
  1129.         break;
  1130.  
  1131.         case 1:
  1132.         x = unchar(data[i]);
  1133.         if ((x < KRM_MINTIMEOUT) || (x > KRM_MAXTIMEOUT))
  1134.             x = KRM_DEFTIMEOUT;
  1135.         krm_sndinit.timeout = x;
  1136.         break;
  1137.  
  1138.         case 2:
  1139.         x = unchar(data[i]);
  1140.         if (x > KRM_MAXPADCOUNT)
  1141.             x = 0;
  1142.         krm_sndinit.padcount = x;
  1143.         break;
  1144.  
  1145.         case 3:
  1146.         x = ctl(data[i]);
  1147.         krm_sndinit.padchar = (BYTE)x;
  1148.         break;
  1149.  
  1150.         case 4:
  1151.         x = unchar(data[i]);
  1152.         if ((x < 1) || (x > 31))
  1153.             x = CR;
  1154.         krm_sndinit.eol = (BYTE)x;
  1155.         break;
  1156.  
  1157.         case 5:
  1158.         x = data[i];
  1159.         x = ((x > 32 && x < 63) || (x > 95 && x < 127)) ? x : '#';
  1160.         krm_sndinit.quote = (BYTE)x;
  1161.         break;
  1162.  
  1163.         case 6:
  1164.         krmSet8BitQuote(data[i]);
  1165.         break;
  1166.  
  1167.         case 7:
  1168.         x = data[i] - '0';
  1169.         if ((x < 1) || (x > 3))
  1170.             x = KRM_DEFBLOCKCHECK;
  1171.         Kermit.bctr = x;
  1172.         break;
  1173.  
  1174.         case 8:
  1175.         x = data[i];
  1176.         if (Kermit.rptflag = ((x > 32 && x < 63) || (x > 95 && x < 127)))
  1177.             krm_rcvinit.rpquote = krm_sndinit.rpquote = (BYTE)x;
  1178.         break;
  1179.  
  1180.         default:
  1181.         return;
  1182.     }
  1183.     }
  1184. }
  1185.  
  1186. /*
  1187.  * krmShowMessage
  1188.  *
  1189.  * Show a message according to a given string ID in the resource file
  1190.  * or from a remote Kermit's error packet.
  1191.  */
  1192. void FAR krmShowMessage(int msgnum)
  1193. {
  1194.  
  1195.     BYTE buf[KRM_MAXPACKETSIZE + 1];
  1196.     BYTE appname[20];
  1197.  
  1198.     int len = krm_rcvpkt.len;
  1199.  
  1200.     if (msgnum == KRM_ERROR_PACKET)
  1201.     krm_decode(buf, krm_rcvpkt.data, &len);
  1202.     else
  1203.         LoadString(Kermit.hInst, msgnum, (LPSTR)buf, sizeof(buf));
  1204.  
  1205.     LoadString(Kermit.hInst, IDS_KRM_KERMIT, appname, sizeof(appname));
  1206.     MessageBox(GetFocus(), buf, appname, MB_ICONASTERISK | MB_OK);
  1207.  
  1208. }
  1209.  
  1210. /*
  1211.  * krmWndCommand
  1212.  *
  1213.  * Process WM_COMMAND message, returning FALSE if
  1214.  * not handled, and TRUE otherwise.
  1215.  * This routine should be placed in the terminal's
  1216.  * WM_COMMAND processor before any other menu commands.
  1217.  * If krmWndCommand returns FALSE, then the terminal
  1218.  * should call its own WM_COMMAND routine.
  1219.  */
  1220. BOOL FAR krmWndCommand(HWND hWnd, WORD mode)
  1221. {
  1222.  
  1223.     switch(mode) {
  1224.  
  1225.     case IDM_KRM_RECEIVE:
  1226.         Kermit.mode = mode;
  1227.         Kermit.start = 'v';
  1228.         wart();
  1229.         break;
  1230.  
  1231.     case IDM_KRM_SEND:
  1232.         Kermit.mode = mode;
  1233.         if (krmOpenDlgBox(hWnd, (FARPROC)krmSendFileProc, DT_KRM_SENDFILE)) {
  1234.              Kermit.start = 's';
  1235.             wart();
  1236.         }
  1237.         break;
  1238.  
  1239.     case IDM_KRM_PROTOCOL:
  1240.         krmOpenDlgBox(hWnd, (FARPROC)krmProtocol, DT_KRM_PROTOCOL);
  1241.         break;
  1242.  
  1243.     case IDM_KRM_PACKETS:
  1244.         krmOpenDlgBox(hWnd, (FARPROC)krmPackets, DT_KRM_PACKETS);
  1245.         break;
  1246.  
  1247.     case IDM_KRM_FILEABORT:
  1248.         Kermit.abort = KRM_FILEABORT;
  1249.         break;
  1250.  
  1251.     case IDM_KRM_BATCHABORT:
  1252.         Kermit.abort = KRM_BATCHABORT;
  1253.         break;
  1254.  
  1255.     case IDM_KRM_ERRORABORT:
  1256.          krm_errpkt(IDS_KRM_CANCELLED);
  1257. /* fall thru */
  1258.  
  1259.     case IDM_KRM_CANCEL:
  1260.          krmCreatePseudoPacket('E', PS_DONE, IDS_KRM_CANCELLED);
  1261.          break;
  1262.  
  1263.     default:
  1264.         return FALSE;
  1265.     }
  1266.     return TRUE;
  1267. }
  1268.  
  1269. /*
  1270.  * krm_errpkt
  1271.  *
  1272.  * Send an error packet to the remote Kermit according
  1273.  * to the resource string ID requested.
  1274.  */
  1275. static void NEAR krm_errpkt(int msgnum)
  1276. {
  1277.     char szMessage[80];
  1278.     BYTE buf[KRM_MAXDATALEN + 1];
  1279.     int inlen, outlen;
  1280.     
  1281.     inlen = LoadString(Kermit.hInst, msgnum, (LPSTR)szMessage, sizeof(szMessage));
  1282.     outlen = krm_encode(buf, szMessage, Kermit.maxsenddatalen, &inlen);
  1283.  
  1284.     krm_spack('E', Kermit.seq, outlen, szMessage);
  1285.  
  1286. }
  1287.  
  1288. /*
  1289.  * krmCreatePseudoPacket
  1290.  *
  1291.  * Handle an internal error as if an error packet were
  1292.  * received from a remote Kermit
  1293.  */
  1294. void NEAR krmCreatePseudoPacket(char type, short state, int msgnum)
  1295. {
  1296.     krm_rcvpkt.type = type;
  1297.     krm_rcvpkt.state = state;
  1298.     krm_rcvpkt.len = LoadString(Kermit.hInst, msgnum, krm_rcvpkt.data, sizeof(krm_rcvpkt.data));
  1299. }
  1300.  
  1301. /*
  1302.  * krm_resend
  1303.  *
  1304.  * If krm_sndpkt is not empty, send it again.
  1305.  * Otherwise, send a NAK
  1306.  */
  1307. void NEAR krm_resend(void)
  1308. {
  1309.     char buf[40];
  1310.     register int len = strlen(krm_sndpkt);
  1311.  
  1312.     if (len)
  1313.         krmWriteComm(*krmcid, krm_sndpkt, len);
  1314.     else
  1315.     krm_nak();
  1316.  
  1317.     if (KermParams.verbose)
  1318.     krmUpdateXferBox(IDD_KRM_RETRIES, itoa(Kermit.totalretries, buf, 10));
  1319.  
  1320. }
  1321.  
  1322. /*
  1323.  * krmUpdateXferBox
  1324.  *
  1325.  * Update a field in the tranfer dialog box
  1326.  */
  1327. static void NEAR krmUpdateXferBox(WORD id, char *str)
  1328. {
  1329.  
  1330.     if (IsWindow(Kermit.hWndXfer))
  1331.         SetDlgItemText(Kermit.hWndXfer, id, str);    
  1332.  
  1333. }
  1334.  
  1335. /*
  1336.  * krm_nak
  1337.  *
  1338.  * Send a negative acknowledgment packet
  1339.  */
  1340. static void NEAR krm_nak()
  1341. {
  1342.  
  1343.     krm_spack('N', Kermit.seq, 0, "");
  1344.  
  1345. }
  1346.  
  1347. /*
  1348.  * krmOpenReceiveFile
  1349.  *
  1350.  * Open a file for writing and return its handle.
  1351.  * If the file exists and file warning is on, then
  1352.  * create a new name for it.
  1353.  */
  1354. static HANDLE NEAR krmOpenReceiveFile(BYTE *inbuf)
  1355. {
  1356.  
  1357.     register int i, j;
  1358.     char filename[13];
  1359.     char ext[5];
  1360.     int numresult;
  1361.     char *ptrresult;
  1362.     BOOL gotextension;
  1363.     HANDLE hfile;
  1364.     char tempname[9], genstring[20];
  1365.     unsigned filecount;
  1366.  
  1367.     memset(filename, NUL, 13);
  1368.     ext[0] = NUL;
  1369.  
  1370.     ptrresult = strtok(inbuf, ".");        /* look for any extension */
  1371.     numresult = strlen(ptrresult);        /* find out how long */
  1372.     numresult = numresult < 8 ? numresult : 8;
  1373.     strncpy(filename,ptrresult,numresult);    /* load up name */
  1374.  
  1375.     gotextension = FALSE;
  1376.     ptrresult = strtok(NULL, ".");        /* get extension */
  1377.     if (ptrresult != NULL) {
  1378.     strcpy(ext,".");
  1379.     strncat(ext, ptrresult,3);
  1380.     ext[4] = NUL;
  1381.     strcat(filename, ext);
  1382.     gotextension = TRUE;
  1383.     }
  1384.  
  1385.     if (KermParams.FileWarning) {
  1386.     for (filecount = 0; filecount < UINT_MAX; filecount++) {
  1387.             if ((hfile = OpenFile((LPSTR)filename,
  1388.              (OFSTRUCT FAR *)&Kermit.fstruct,OF_EXIST)) == -1)
  1389.             break;
  1390.         ptrresult = strtok(filename, ".");
  1391.         strcpy(tempname, ptrresult);        
  1392.         numresult = strlen(ptrresult);        
  1393.         for (i = numresult; i < 8; i++)        
  1394.             tempname[i] = '0';
  1395.         numresult = strlen(itoa(filecount + 1, genstring,10));        
  1396.  
  1397.         for (i = 8 - numresult, j = 0; i < 8; i++,j++)
  1398.             tempname[i] = genstring[j];        
  1399.         tempname[8] = NUL;
  1400.         strcpy(filename, tempname);
  1401.         if (gotextension)
  1402.             strcat(filename,ext);
  1403.     }
  1404.     }
  1405.     hfile = OpenFile((LPSTR)filename,(OFSTRUCT FAR *)&Kermit.fstruct,OF_CREATE);
  1406.     return (hfile);
  1407. }
  1408.  
  1409. /*
  1410.  * krmWriteComm
  1411.  *
  1412.  * Write data to comm port.  Add padding if required
  1413.  */
  1414. static short NEAR krmWriteComm(int cid, BYTE *buf, int len)
  1415. {
  1416.  
  1417.     if (krm_sndinit.padcount) {
  1418.     BYTE padbuf[KRM_MAXPADCOUNT];
  1419.     memset(padbuf, krm_sndinit.padchar, krm_sndinit.padcount);
  1420.     WriteComm(cid, padbuf, krm_sndinit.padcount);
  1421.     }
  1422.     return WriteComm(cid, buf, len);
  1423. }
  1424.  
  1425. /*
  1426.  * krmHideChildren
  1427.  *
  1428.  * Child Windows enumeration call back function
  1429.  */
  1430. BOOL FAR PASCAL krmHideChildren(HWND hWnd, LONG lParam)
  1431. {
  1432.     ShowWindow(hWnd, LOWORD(lParam));
  1433.     return TRUE;
  1434. }
  1435.  
  1436. /*
  1437.  * krmDoTimeout
  1438.  *
  1439.  * Timer call back function
  1440.  */
  1441. void FAR PASCAL krmDoTimeout(HWND hWnd,unsigned message,short event,DWORD time)
  1442. {
  1443.  
  1444.     switch(event) {
  1445.     case KRM_WAITPACKET:
  1446.         if (KermParams.Bell)
  1447.         MessageBeep(0);
  1448.         krm_rcvpkt.state = PS_DONE;
  1449.         krm_rcvpkt.type = 'T';
  1450.         break;
  1451.  
  1452.     case KRM_WAITSEND:
  1453.         Kermit.delay = FALSE;
  1454.         KillTimer(hWnd, event);
  1455.         break;
  1456.  
  1457.     default:
  1458.         KillTimer(hWnd, event);
  1459.         break;
  1460.     }
  1461. }
  1462.  
  1463. /*
  1464.  * krm_checkcnx
  1465.  *
  1466.  * Examine ack data packet for remote cancel command
  1467.  */
  1468. void NEAR krm_checkcnx()
  1469. {
  1470.  
  1471.     if (krm_rcvpkt.len > 0) {
  1472.     switch(krm_rcvpkt.data[0]) {
  1473.         case 'X':
  1474.         Kermit.abort = KRM_FILEABORT;
  1475.         break;
  1476.         case 'Z':
  1477.         Kermit.abort = KRM_BATCHABORT;
  1478.         break;
  1479.         default:
  1480.         Kermit.abort = 0;
  1481.     }
  1482.     }
  1483. }
  1484.  
  1485. /*
  1486.  * krmPaint
  1487.  *
  1488.  * Draw the lower four bits of the packet count
  1489.  * in the icon window if iconic
  1490.  */
  1491. void FAR krmPaint(HWND hWnd, HDC hDC)
  1492. {
  1493.     char buf[20];
  1494.     RECT rect;
  1495.  
  1496.     GetClientRect(hWnd, &rect);
  1497.     itoa(LOWORD(Kermit.packetcount), buf, 10),
  1498.     DrawText(hDC, buf, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
  1499. }
  1500.  
  1501. /*
  1502.  * krm_savename
  1503.  *
  1504.  * Decode and display the name under which the file
  1505.  * is saved on the remote Kermit
  1506.  */
  1507. void NEAR krm_savename()
  1508. {
  1509.     BYTE buf[KRM_MAXPACKETSIZE + 1];
  1510.     int len = krm_rcvpkt.len;
  1511.  
  1512.     if (len > 0) {
  1513.     krm_decode(buf, krm_rcvpkt.data, &len);
  1514.         if (KermParams.verbose)
  1515.             krmUpdateXferBox(IDD_KRM_SAVENAME, buf);
  1516.     }
  1517. }
  1518.  
  1519. /*
  1520.  * krmFlushQue
  1521.  *
  1522.  * Flush the communications port and the internal buffer
  1523.  */
  1524. void NEAR krmFlushQue()
  1525. {
  1526.     FlushComm(*krmcid, 0); /* flush send and rececive comm driver queues */
  1527.     FlushComm(*krmcid, 1);
  1528.     *krmBuflen = 0;       /* flush local buffer */
  1529. }
  1530.